package com.liao.tensquare.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.liao.tensquare.constants.TokenConstants;
import com.liao.tensquare.entity.JWTInfo;
import com.liao.tensquare.entity.Result;
import com.liao.tensquare.entity.StatusCode;
import com.liao.tensquare.exception.UserTokenException;
import com.liao.tensquare.utils.JwtTokenUtil;
import com.liao.tensquare.utils.RedisConstant;
import com.liao.tensquare.utils.StringHelper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@Slf4j
@Configuration
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {

    private final ObjectMapper objectMapper = new ObjectMapper();
    private static final String startWith = "/auth/captcha,/auth/token,/api/admin/user/reg,/avatars/";

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("path:->{}", request.getMethod() + ":" + request.getRequestURI());
        if (checkUrl(request.getRequestURI()) || request.getMethod().equals("OPTIONS")) {
            return true;
        }
        String token = request.getHeader("authentication");
        return checkToken(token, request, response);
    }

    private void getRequestBody(HttpServletRequest request) throws IOException {
        HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(request);
        String body = requestWrapper.getBody();
//        String data;
//        StringBuilder body = new StringBuilder();
//        while ((data = reader.readLine()) != null) {
//            body.append(data);
//        }
        log.info("body->{}", body.toString());
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        super.afterCompletion(request, response, handler, ex);
    }

    /**
     * 验证是否要拦截URL
     */
    private boolean checkUrl(String url) {
        for (String s : startWith.split(",")) {
            if (url.startsWith(s)) {
                return true;
            }
        }
        return false;
    }

    private boolean checkToken(String token, HttpServletRequest request, HttpServletResponse response) throws IOException {
        Claims infoFromToken = null;
        try {
            if (StringHelper.isEmpty(token)) {
                response.setContentType("text/html;charset=utf-8");
                Result result = new Result(false, "Token不能为空", StatusCode.USER_TOKEN_ERROR);
                response.getWriter().write(objectMapper.writeValueAsString(result));
                return false;
            }
            infoFromToken = JwtTokenUtil.getInfoFromToken(token, TokenConstants.SECRET_KEY);
            JWTInfo jwtInfo = getJWTInfo(infoFromToken);
            String s = redisTemplate.opsForValue().get(RedisConstant.REDIS_USER_INFO_KEY + ":" + jwtInfo.getId());
            if (null == s) {
                throw new UserTokenException("token过期");
            }
            request.setAttribute(TokenConstants.JWT_USER_ID, jwtInfo.getId());
            request.setAttribute(TokenConstants.JWT_KEY_NICKNAME, jwtInfo.getNickname());
            return true;
        } catch (Exception e) {
            Result result;
            if (e instanceof ExpiredJwtException) {
                result = new Result(false, "JWT已过期", StatusCode.USER_TOKEN_EXPIRED);
            } else {
                result = new Result(false, e.getMessage(), StatusCode.USER_TOKEN_ERROR);
            }
            //解决中文乱码
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(objectMapper.writeValueAsString(result));
        }
        //拦截器返回false，那客户端的请求就不会往后面走，所以后面配置的跨域就会失效，需要重新配置
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "*");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
        response.addHeader("Access-Control-Max-Age", "3600");
        return false;
    }

    /**
     * 获取用户JWT的信息
     */
    private JWTInfo getJWTInfo(Claims infoFromToken) {
        return new JWTInfo(StringHelper.getObjectValue(infoFromToken.get(TokenConstants.JWT_KEY_USER_ACCOUNT)),
                StringHelper.getObjectValue(infoFromToken.get(TokenConstants.JWT_KEY_NICKNAME)),
                StringHelper.getObjectValue(infoFromToken.get(TokenConstants.JWT_KEY_ID)));
    }

}
